package com.jkgh.remedium.rsgen.parser;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.jkgh.remedium.rsgen.vo.Argument;
import com.jkgh.remedium.rsgen.vo.DataObject;
import com.jkgh.remedium.rsgen.vo.FieldInfo;
import com.jkgh.remedium.rsgen.vo.MethodInfo;
import com.jkgh.remedium.rsgen.vo.MethodObject;
import com.jkgh.remedium.rsgen.vo.RemediumSystem;
import com.jkgh.remedium.rsgen.vo.Return;

public class RemediumSystemParser {

	public static RemediumSystem parse(File xmlFile) throws ParserConfigurationException, IOException, SAXException {

		Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);

		Element element = dom.getDocumentElement();

		if (element.getNodeName().equals("RemediumSystem")) {
			RemediumSystem rs = new RemediumSystem(element.getAttribute("name"), element.getAttribute("package"), element.getAttribute("description"), element.getAttribute("accessClass"));

			NodeList mosOrDos = element.getChildNodes();

			for (int i = 0; i < mosOrDos.getLength(); ++i) {
				Node moOrDoNode = mosOrDos.item(i);

				if (moOrDoNode.getNodeType() == Node.ELEMENT_NODE) {
					Element moOrDo = (Element) moOrDoNode;
					if (moOrDo.getNodeName().equals("MethodObject")) {

						MethodObject mo = new MethodObject(moOrDo.getAttribute("class"), moOrDo.getAttribute("description"));
						NodeList methods = moOrDo.getChildNodes();

						for (int j = 0; j < methods.getLength(); ++j) {
							Node methodNode = methods.item(j);

							if (methodNode.getNodeType() == Node.ELEMENT_NODE) {
								Element method = (Element) methodNode;
								if (method.getNodeName().equals("Method")) {
									MethodInfo m = new MethodInfo(method.getAttribute("name"), method.getAttribute("description"));

									NodeList argsOrReturn = method.getChildNodes();
									for (int k = 0; k < argsOrReturn.getLength(); ++k) {
										Node argOrReturnNode = argsOrReturn.item(k);
										if (argOrReturnNode.getNodeType() == Node.ELEMENT_NODE) {
											Element argOrReturn = (Element) argOrReturnNode;
											if (argOrReturn.getNodeName().equals("Argument")) {
												Argument arg = new Argument(argOrReturn.getAttribute("class"), argOrReturn.getAttribute("name"), argOrReturn.getAttribute("description"));
												m.addArgument(arg);
											} else if (argOrReturn.getNodeName().equals("Return")) {
												Return ret = new Return(argOrReturn.getAttribute("class"), argOrReturn.getAttribute("description"));
												m.setReturnType(ret);
											} else {
												throw new RuntimeException("Argument or Return expected, but " + argOrReturn.getNodeName() + " found.");
											}
										}
									}

									mo.addMethod(m);
								} else {
									throw new RuntimeException("Method expected, but " + method.getNodeName() + " found.");
								}
							}
						}
						rs.addMethodObject(mo);

					} else if (moOrDo.getNodeName().equals("DataObject")) {

						DataObject doo = new DataObject(moOrDo.getAttribute("class"), moOrDo.getAttribute("description"));
						NodeList fields = moOrDo.getChildNodes();

						for (int j = 0; j < fields.getLength(); ++j) {
							Node fieldNode = fields.item(j);

							if (fieldNode.getNodeType() == Node.ELEMENT_NODE) {
								Element field = (Element) fieldNode;
								if (field.getNodeName().equals("Field")) {
									FieldInfo f = new FieldInfo(field.getAttribute("class"), field.getAttribute("name"), field.getAttribute("description"));
									doo.addField(f);
								} else {
									throw new RuntimeException("Field expected, but " + field.getNodeName() + " found.");
								}
							}
						}
						rs.addDataObject(doo);

					} else {
						throw new RuntimeException("MethodObject or DataObject expected, but " + moOrDo.getNodeName() + " found.");
					}
				}
			}

			return rs;
		} else {
			throw new RuntimeException("RemediumSystem expected, but " + element.getNodeName() + " found.");
		}
	}
}
